Dear Yordan,
Kindly find attached a folder containing python code for the toy model in the stock flow presentation. The coding of system wide stress simulation is part of my deliverables. In addition, I thought it may be useful for you to have an object orientated programming framework in python because it is associated with agent based modelling. In object-oriented programming languages, data and programming methods or functions are “embedded” in objects that can manipulate their own data and interact with other programming objects. This makes real-world entities such as households or banks easy to be represented. For example, in this model a natural starting point is to define an object/class called “Dealer banks”. I specified information dealers would need to have and rules for how they interact with each other and their environment. Another feature of object-oriented programming that is good for ABM development is inheritance. An instantiated object, e.g. commercial bank, can ‘inherit’ some characteristics from a ‘parent class’ but still behave in different ways.
However, the obvious downside is that Python coding is definitely harder than Matlab. For example, there is no interface to click on a variable set(not that I"m aware of anyway), you have to save the variables in a dataframe (by writing a function in the code) and then write the dataframe to a csv file. On the upside, it’s possible to automate the update state easily and add heterogenous behavior for same-type like institutions. Another feature is that
Running python : For python code to be executed the computer needs to have python 2 or python 3 installed (via https://www.python.org) A nice coding editor like Sublime Text 3, Atom or pycharm. The good thing about pycharm is that you can run the code in the editor without installing additional packages. On my mac, I actually run the code in the terminal (also called bash). I think in Windows, the equivalent is the shell. The program is run via command line codes. So I go to the path of where the folders are stored and type.
python sflow.py
Alternatively, for example in pycharm, you can open the slfow.py program and then run it.
This executes the whole program and writes a csv file with the output in the main folder stockflow
.
If you want to change things in this model, the main files you will be working on are the agent scripts
in src/institution, the updater.py and the configuration files in /configs/.
So let's start by looking at the main file:
In [3]:
# %load sflow.py
# [SublimeLinter pep8-max-line-length:300]
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------
#
# MAIN
#
# -------------------------------------------------------------------------
if __name__ == '__main__':
from src.environment import Environment
from src.runner import Runner
# We have to pass in the path of the environment xml as args[0]
# the name of the environment xml as args[1] here:
# and the scenario name as args[2] here:
args = ["configs/environment/", "environment_config", "benchmark"]
#
# INITIALIZATION
#
environment_directory = str(args[0])
identifier = str(args[1])
scenario = str(args[2])
environment = Environment(environment_directory, identifier)
runner = Runner(environment, scenario)
#
# UPDATE STEP
#
for i in range(int(environment.static_parameters['num_simulations'])):
environment.initialize(environment_directory, identifier)
runner.initialize(environment, scenario)
# do the run
runner.do_run(environment, scenario)
In the beginning we need to instantiate two objects in the main file to run the program -
from src.environment import Environment
from src.runner import Runner
the Environment and the Runner class. The code for those classes are stored in the folder src and the name of the classes are Environment and Runner (not surprising).
for hr in environment.hedgefunds:
print hr.Cash
The instantiation of the agents takes up quite a bit of code in the environment file. The code reads the data for the agents from configuration files you find in /configs. A configuration file for the agents is stored in an agent folder because python iterates through the folder to look for all config files for a specific agent. It's possible to store them all in one place but then the automation code of the instantiation has to be changed. An agent config file looks like this:
In [4]:
# %load configs/agents/hf/hf.xml
<agent identifier="HF">
<parameter type="stock_variables" name="GB" value="40"></parameter>
<parameter type="stock_variables" name="CB" value="20"></parameter>
<parameter type="stock_variables" name="Cash" value="10"></parameter>
<parameter type="stock_variables" name="does_repo" value="yes"></parameter>
</agent>
<!-- <parameter type="parameters" name="leverage" value="13.0780116888061"></parameter> -->
Those type " " names later become dictionaries for the instantiated agent object. So the hedge fund has a dictionary (a data structure that saves stuff) with the name stock_variable = {Cash: 20, GB: 40, CB: 20, does_repo = 'yes'} When I write the results to csv, I iterate over those variables. You can define additional variables (e.g. leverage) by adding a line. But for now I commented that out. Agents' configuration files all look similar to that one. The environment config file looks a bit different:
In [ ]:
# %load configs/environment/environment_config.xml
<environment identifier='toy_test'>
<!-- simulation parameters -->
<parameter type='static' name='num_sweeps' value='10'></parameter>
<parameter type='static' name='num_simulations' value='1'></parameter>
<parameter type='static' name='cbank_directory' value='configs/agents/cbank/'></parameter>
<parameter type='static' name='dealer_directory' value='configs/agents/dealer/'></parameter>
<parameter type='static' name='hf_directory' value='configs/agents/hf/'></parameter>
<parameter type='static' name='pf_directory' value='configs/agents/pf/'></parameter>
<parameter type='static' name='ic_directory' value='configs/agents/ic/'></parameter>
<parameter type='static' name='mmf_directory' value='configs/agents/mmf/'></parameter>
<parameter type='static' name='if_directory' value='configs/agents/if/'></parameter>
<parameter type='exogenous' name='price_GB' value="1.0"></parameter>
<parameter type='exogenous' name='price_CB' value="1.0"></parameter>
<parameter type='exogenous' name='haircut' value="0.05"></parameter>
<parameter type='exogenous' name='interest_GB' value="0.02"></parameter>
<parameter type='exogenous' name='interest_CB' value="0.04"></parameter>
<parameter type='exogenous' name='interest_repo' value="0.02"></parameter>
<parameter type='exogenous' name='interest_loans' value="0.02"></parameter>
<parameter type='exogenous' name='interest_deposits' value="0.02"></parameter>
<parameter type='exogenous' name='GB_shock' value="-0.1"></parameter>
<parameter type='exogenous' name='CB_shock' value="-0.1"></parameter>
<parameter type='exogenous' name='Redemption' value="-0.1"></parameter>
</environment>
Here you can change the initital interest rates and prices for the marketable assets and also the shocks. It's possible to assign them to other variables and change them later in the updater. It's also possible to not read them in at all (just delete the lines) and define those in the updater script, but in the current setup they get read into the dictionary in the environment, environment.exogenous variables = {price_GB : 1.0, ... }.
What's the difference between num_simulations
and num_sweeps
? For the time iterations current_step
it's more convenient to use num_sweeps rather than num_simulations for now. num_sweeps
are the time steps for the model algorithm. With num_simulations, one can initiate a different environment with different classes, so for now it's better to stick with num_sweeps to handle the time steps in the model.
Once all the agents' objects and configuration files are instantiated, the code moves on to the actual model algorithm which is stored in the updater class under \src\
updater.py
The updater can be thought as the class that handels the transition.
Here
def add_rates(self, environment):
def initialize_prices
and def updade_prices
The really important method is the one below:
def do_update_benchmark(self, environment, current_step, scenario):
import pandas as pd
if current_step < 1:
self.add_rates(environment)
self.initialize_prices(environment, current_step)
print "***In t=:", current_step , " This is the price matrix***\n", self.prices, "\n",
self.initialize_assets_all_agents(current_step, environment)
self.profit_all_agents(environment, current_step)
else:
self.update_all_agents_balance_sheets(environment, current_step, scenario)
def write_to_csv
puts the output in to a result dataframe self.results_df.
In [ ]:
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------------
# class Updater
# -------------------------------------------------------------------------
import numpy as np
class Updater():
#
#
# METHODS
#
def get_identifier(self):
return self.identifier
# -------------------------------------------------------------------------
# __init__
# -------------------------------------------------------------------------
def __init__(self, environment, runner):
self.environment = environment
self.runner = runner
self.results_df = 0
self.prices = np.array([])
self.rates={}
self.system_equity = 0
self.system_assets = 0
self.delta_pGB = 0
self.delta_pGB = 0
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# do_update
# -------------------------------------------------------------------------
def do_update_benchmark(self, environment, current_step, scenario):
import pandas as pd
if current_step < 1:
self.add_rates(environment)
self.initialize_prices(environment, current_step)
print "***In t=:", current_step , " This is the price matrix***\n", self.prices, "\n",
self.initialize_assets_all_agents(current_step, environment)
self.profit_all_agents(environment, current_step)
else:
self.update_all_agents_balance_sheets(environment, current_step, scenario)
Last, but not least, we have the agent classes under /src/class_folder where agents' balance sheets and behavior are set. Profit and balance sheet dynamics are found in the respective agent scripts, i.e. hf.py has the profit functions for the hedge fund, pf.py has the profit function and (potential) constraints for the pension fund, etc.
The functions in the agent scripts are:
def initialize_assets
def print_balance_shee
def profit
def check_consistency
def update_balance_sheets
I hope these instructions are sufficient to get you started.
Please let me know if there is anything else I can do to explain.
Hope you are well.
Tina
In [ ]: